#include "CorelSpyAPIProxy.h"
#include <tchar.h>
#include <stdio.h>
#include <shlobj.h>

extern VOID (WINAPI *TrueOutputDebugStringA)(LPCSTR lpOutputString);
extern VOID (WINAPI *TrueOutputDebugStringW)(LPCWSTR lpOutputString);
extern LRESULT (WINAPI *TrueSendMessageA)(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
extern LRESULT (WINAPI *TrueSendMessageW)(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
extern BOOL (WINAPI *TruePostMessageA)(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
extern BOOL (WINAPI *TruePostMessageW)(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
extern long (WINAPI *TrueBroadcastSystemMessageA)(DWORD flags, LPDWORD lpInfo, UINT Msg, WPARAM wParam, LPARAM lParam);
extern long (WINAPI *TrueBroadcastSystemMessageW)(DWORD flags, LPDWORD lpInfo, UINT Msg, WPARAM wParam, LPARAM lParam);
extern long (WINAPI *TrueBroadcastSystemMessageExA)(DWORD flags,LPDWORD lpInfo, UINT Msg, WPARAM wParam, LPARAM lParam, PBSMINFO pbsmInfo);
extern long (WINAPI *TrueBroadcastSystemMessageExW)(DWORD flags,LPDWORD lpInfo, UINT Msg, WPARAM wParam, LPARAM lParam, PBSMINFO pbsmInfo);
extern HMODULE (WINAPI *TrueLoadLibraryA)(LPCSTR lpLibFileName);
extern HMODULE (WINAPI *TrueLoadLibraryW)(LPCWSTR lpLibFileName);
extern HMODULE (WINAPI *TrueLoadLibraryExA)(LPCSTR lpLibFileName, HANDLE hFile, DWORD dwFlags);
extern HMODULE (WINAPI *TrueLoadLibraryExW)(LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags);
extern int (WINAPI *TrueMultiByteToWideChar)(UINT CodePage, DWORD dwFlags, LPCSTR lpMultiByteStr, int cbMultiByte, LPWSTR lpWideCharStr, int cchWideChar);
extern int (WINAPI *TrueWideCharToMultiByte)(UINT CodePage, DWORD dwFlags, LPCWSTR lpWideCharStr, int cchWideChar, LPSTR lpMultiByteStr, int cbMultiByte, LPCSTR lpDefaultChar, LPBOOL lpUsedDefaultChar);

typedef LONG (WINAPI *PFN_RtlMultiByteToUnicodeN)(PWCH UnicodeString, ULONG MaxBytesInUnicodeString, PULONG BytesInUnicodeString, const CHAR *MultiByteString, ULONG BytesInMultiByteString);
extern PFN_RtlMultiByteToUnicodeN TrueRtlMultiByteToUnicodeN;

typedef LONG (WINAPI *PFN_RtlUnicodeToMultiByteN)(PCHAR MultiByteString, ULONG MaxBytesInMultiByteString, PULONG BytesInMultiByteString, PCWCH UnicodeString, ULONG BytesInUnicodeString);
extern PFN_RtlUnicodeToMultiByteN TrueRtlUnicodeToMultiByteN;

typedef LONG (WINAPI *PFN_RtlMultiByteToUnicodeSize)(PULONG BytesInUnicodeString, const CHAR *MultiByteString, ULONG BytesInMultiByteString);
extern PFN_RtlMultiByteToUnicodeSize TrueRtlMultiByteToUnicodeSize;

typedef LONG (WINAPI *PFN_RtlUnicodeToMultiByteSize)(PULONG BytesInMultiByteString, PCWCH UnicodeString, ULONG BytesInUnicodeString);
extern PFN_RtlUnicodeToMultiByteSize TrueRtlUnicodeToMultiByteSize;


CCorelSpyAPIProxy::CCorelSpyAPIProxy(CCorelSpyMediator *pcMediator)
: m_pcMediator(pcMediator)
{
    InitializeCriticalSection(&m_csLock);
}

CCorelSpyAPIProxy::~CCorelSpyAPIProxy()
{
    DeleteCriticalSection(&m_csLock);
}

VOID WINAPI CCorelSpyAPIProxy::OutputDebugStringA(LPCSTR lpOutputString)
{
    std::wstring t_wstrStack;
    m_pcMediator->Enter();
    m_pcMediator->EnableSpy(FALSE);

    TrueOutputDebugStringA(lpOutputString);
    //if (TRUE == m_pcMediator->IsSpyEnabled())
    //{
    //    m_pcMediator->EnableSpy(FALSE);
    //    CONTEXT context;
    //    GET_CURRENT_CONTEXT(context, CONTEXT_FULL);
    //    m_pcMediator->GetSymbolEngine()->StackTrace(&context, 0, t_wstrStack);

    //    TrueOutputDebugStringA("[CorelSpy] Dump call stack of OutputDebugStringA");
    //    TrueOutputDebugStringW(t_wstrStack.c_str());

    //    m_pcMediator->EnableSpy(TRUE);
    //}

    m_pcMediator->EnableSpy(TRUE);
    m_pcMediator->Leave();
}

VOID WINAPI CCorelSpyAPIProxy::OutputDebugStringW(LPCWSTR lpOutputString)
{
    std::wstring t_wstrStack;
    m_pcMediator->Enter();
    m_pcMediator->EnableSpy(FALSE);

    //TrueOutputDebugStringW(lpOutputString);
    //if (TRUE == m_pcMediator->IsSpyEnabled())
    //{
    //    m_pcMediator->EnableSpy(FALSE);
    //    CONTEXT context;
    //    GET_CURRENT_CONTEXT(context, CONTEXT_FULL);
    //    m_pcMediator->GetSymbolEngine()->StackTrace(&context, 2, t_wstrStack);

    //    TrueOutputDebugStringW(t_wstrStack.c_str());

    //   m_pcMediator->EnableSpy(TRUE);
    //}

    m_pcMediator->EnableSpy(TRUE);
    m_pcMediator->Leave();
}

LRESULT WINAPI CCorelSpyAPIProxy::SendMessageA(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
    LRESULT t_ret;
    std::wstring t_wstrStack;
    m_pcMediator->Enter();

    t_ret = TrueSendMessageA(hWnd, Msg, wParam, lParam);
    if (TRUE == m_pcMediator->IsSpyEnabled())
    {
        m_pcMediator->EnableSpy(FALSE);
        CONTEXT context;
        GET_CURRENT_CONTEXT(context, CONTEXT_FULL);
        m_pcMediator->GetSymbolEngine()->StackTrace(&context, 2, t_wstrStack);

        TrueOutputDebugStringW(t_wstrStack.c_str());

        m_pcMediator->EnableSpy(TRUE);
    }

    m_pcMediator->Leave();
    return t_ret;
}

LRESULT WINAPI CCorelSpyAPIProxy::SendMessageW(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
    LRESULT t_ret;
    std::wstring t_wstrStack;
    m_pcMediator->Enter();

    t_ret = TrueSendMessageW(hWnd, Msg, wParam, lParam);
    if (TRUE == m_pcMediator->IsSpyEnabled())
    {
        m_pcMediator->EnableSpy(FALSE);
        CONTEXT context;
        GET_CURRENT_CONTEXT(context, CONTEXT_FULL);
        m_pcMediator->GetSymbolEngine()->StackTrace(&context, 2, t_wstrStack);

        TrueOutputDebugStringW(t_wstrStack.c_str());

        m_pcMediator->EnableSpy(TRUE);
    }

    m_pcMediator->Leave();
    return t_ret;
}

BOOL WINAPI CCorelSpyAPIProxy::PostMessageA(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
    BOOL t_ret;
    std::wstring t_wstrStack;
    m_pcMediator->Enter();

    t_ret = TruePostMessageA(hWnd, Msg, wParam, lParam);
    if (TRUE == m_pcMediator->IsSpyEnabled())
    {
        m_pcMediator->EnableSpy(FALSE);
        CONTEXT context;
        GET_CURRENT_CONTEXT(context, CONTEXT_FULL);
        m_pcMediator->GetSymbolEngine()->StackTrace(&context, 2, t_wstrStack);

        TrueOutputDebugStringA("[CorelSpy] StackTrace - PostMessageA\n");
        TrueOutputDebugStringW(t_wstrStack.c_str());

        m_pcMediator->EnableSpy(TRUE);
    }

    m_pcMediator->Leave();
    return t_ret;
}

BOOL WINAPI CCorelSpyAPIProxy::PostMessageW(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
    BOOL t_ret;
    std::wstring t_wstrStack;
    m_pcMediator->Enter();

    t_ret = TruePostMessageW(hWnd, Msg, wParam, lParam);
    if (TRUE == m_pcMediator->IsSpyEnabled())
    {
        m_pcMediator->EnableSpy(FALSE);
        CONTEXT context;
        GET_CURRENT_CONTEXT(context, CONTEXT_FULL);
        m_pcMediator->GetSymbolEngine()->StackTrace(&context, 2, t_wstrStack);

        TrueOutputDebugStringA("[CorelSpy] StackTrace - PostMessageW\n");
        TrueOutputDebugStringW(t_wstrStack.c_str());

        m_pcMediator->EnableSpy(TRUE);
    }

    m_pcMediator->Leave();
    return t_ret;
}

long WINAPI CCorelSpyAPIProxy::BroadcastSystemMessageA(DWORD flags, LPDWORD lpInfo, UINT Msg, WPARAM wParam, LPARAM lParam)
{
    BOOL t_ret;
    std::wstring t_wstrStack;
    m_pcMediator->Enter();

    t_ret = TrueBroadcastSystemMessageA(flags, lpInfo, Msg, wParam, lParam);
    if (TRUE == m_pcMediator->IsSpyEnabled())
    {
        m_pcMediator->EnableSpy(FALSE);
        CONTEXT context;
        GET_CURRENT_CONTEXT(context, CONTEXT_FULL);
        m_pcMediator->GetSymbolEngine()->StackTrace(&context, 2, t_wstrStack);

        TrueOutputDebugStringW(t_wstrStack.c_str());

        m_pcMediator->EnableSpy(TRUE);
    }

    m_pcMediator->Leave();
    return t_ret;
}

long WINAPI CCorelSpyAPIProxy::BroadcastSystemMessageW(DWORD flags, LPDWORD lpInfo, UINT Msg, WPARAM wParam, LPARAM lParam)
{
    BOOL t_ret;
    std::wstring t_wstrStack;
    m_pcMediator->Enter();

    t_ret = TrueBroadcastSystemMessageW(flags, lpInfo, Msg, wParam, lParam);
    if (TRUE == m_pcMediator->IsSpyEnabled())
    {
        m_pcMediator->EnableSpy(FALSE);
        CONTEXT context;
        GET_CURRENT_CONTEXT(context, CONTEXT_FULL);
        m_pcMediator->GetSymbolEngine()->StackTrace(&context, 2, t_wstrStack);

        TrueOutputDebugStringW(t_wstrStack.c_str());

        m_pcMediator->EnableSpy(TRUE);
    }

    m_pcMediator->Leave();
    return t_ret;
}

long WINAPI CCorelSpyAPIProxy::BroadcastSystemMessageExA(DWORD flags,LPDWORD lpInfo, UINT Msg, WPARAM wParam, LPARAM lParam, PBSMINFO pbsmInfo)
{
    BOOL t_ret;
    std::wstring t_wstrStack;
    m_pcMediator->Enter();

    t_ret = TrueBroadcastSystemMessageExA(flags, lpInfo, Msg, wParam, lParam, pbsmInfo);
    if (TRUE == m_pcMediator->IsSpyEnabled())
    {
        m_pcMediator->EnableSpy(FALSE);
        CONTEXT context;
        GET_CURRENT_CONTEXT(context, CONTEXT_FULL);
        m_pcMediator->GetSymbolEngine()->StackTrace(&context, 2, t_wstrStack);

        TrueOutputDebugStringW(t_wstrStack.c_str());

        m_pcMediator->EnableSpy(TRUE);
    }

    m_pcMediator->Leave();
    return t_ret;
}

long WINAPI CCorelSpyAPIProxy::BroadcastSystemMessageExW(DWORD flags,LPDWORD lpInfo, UINT Msg, WPARAM wParam, LPARAM lParam, PBSMINFO pbsmInfo)
{
    BOOL t_ret;
    std::wstring t_wstrStack;
    m_pcMediator->Enter();

    t_ret = TrueBroadcastSystemMessageExW(flags, lpInfo, Msg, wParam, lParam, pbsmInfo);
    if (TRUE == m_pcMediator->IsSpyEnabled())
    {
        m_pcMediator->EnableSpy(FALSE);
        CONTEXT context;
        GET_CURRENT_CONTEXT(context, CONTEXT_FULL);
        m_pcMediator->GetSymbolEngine()->StackTrace(&context, 2, t_wstrStack);

        TrueOutputDebugStringW(t_wstrStack.c_str());

        m_pcMediator->EnableSpy(TRUE);
    }

    m_pcMediator->Leave();
    return t_ret;
}

HMODULE WINAPI CCorelSpyAPIProxy::LoadLibraryA(LPCSTR lpLibFileName)
{
    HMODULE t_ret;
    std::wstring t_wstrStack;
    m_pcMediator->Enter();

    t_ret = TrueLoadLibraryA(lpLibFileName);

    m_pcMediator->Leave();
    return t_ret;
}

HMODULE WINAPI CCorelSpyAPIProxy::LoadLibraryW(LPCWSTR lpLibFileName)
{
    HMODULE t_ret;
    std::wstring t_wstrStack;
    m_pcMediator->Enter();

    t_ret = TrueLoadLibraryW(lpLibFileName);

    m_pcMediator->Leave();
    return t_ret;
}

HMODULE WINAPI CCorelSpyAPIProxy::LoadLibraryExA(LPCSTR lpLibFileName, HANDLE hFile, DWORD dwFlags)
{
    HMODULE t_ret;
    std::wstring t_wstrStack;
    m_pcMediator->Enter();

    t_ret = TrueLoadLibraryExA(lpLibFileName, hFile, dwFlags);

    m_pcMediator->Leave();
    return t_ret;
}

HMODULE WINAPI CCorelSpyAPIProxy::LoadLibraryExW(LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags)
{
    HMODULE t_ret = NULL;
    std::wstring t_wstrStack;
    m_pcMediator->Enter();

    if (TRUE == m_pcMediator->IsSpyEnabled())
    {
        // Disable API Spy to avoid deadlock with loader lock
        m_pcMediator->EnableSpy(FALSE);

        t_ret = TrueLoadLibraryExW(lpLibFileName, hFile, dwFlags);

        char t_szModule[1024];
        TrueWideCharToMultiByte(CP_ACP, 0, lpLibFileName, (int)wcslen(lpLibFileName)+1, t_szModule, 1024, 0, 0);
        if (t_ret) 
        {
            m_pcMediator->GetSymbolEngine()->LoadSymbol(t_ret, t_szModule);
        }
        else
        {
            char t_szTmp[1024];
            sprintf_s(t_szTmp, sizeof(t_szTmp), "[CorelSpy] Load Library(%s) failed!\n", t_szModule);
        }

        m_pcMediator->EnableSpy(TRUE);
    }
    else
    {
        t_ret = TrueLoadLibraryExW(lpLibFileName, hFile, dwFlags);
    }
    m_pcMediator->Leave();
    return t_ret;
}

int WINAPI CCorelSpyAPIProxy::MultiByteToWideChar(UINT CodePage, DWORD dwFlags, LPCSTR lpMultiByteStr, int cbMultiByte, LPWSTR lpWideCharStr, int cchWideChar)
{
    int t_ret;
    std::wstring t_wstrStack;
    m_pcMediator->Enter();

    t_ret = TrueMultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cbMultiByte, lpWideCharStr, cchWideChar);
    if (TRUE == m_pcMediator->IsSpyEnabled() && cchWideChar)
    {
        m_pcMediator->EnableSpy(FALSE);

        // Check whether it can be converted back to original string
        DWORD t_dwSize = TrueWideCharToMultiByte(CodePage, 0, lpWideCharStr, t_ret, 0, 0, 0, 0);
        LPSTR t_szMultiByteStr = (LPSTR)HeapAlloc(GetProcessHeap(), 0, t_dwSize*sizeof(CHAR));
        int t_nRevert = TrueWideCharToMultiByte(CodePage, 0, lpWideCharStr, t_ret, t_szMultiByteStr, t_dwSize, 0, 0);
        if (strncmp(lpMultiByteStr, t_szMultiByteStr, t_dwSize))
        {
            CONTEXT context;
            GET_CURRENT_CONTEXT(context, CONTEXT_FULL);
            m_pcMediator->GetSymbolEngine()->StackTrace(&context, 1, t_wstrStack);

            if (m_pcMediator->GetStackTraceMgr()->GetStackTraceId(t_wstrStack.c_str()) != (DWORD)-1)
            {
                {
                    CHAR t_szBuf[1024];
                    sprintf_s(t_szBuf, "[CorelSpy] There is a Unicode conversion problem in MultiByteToWideChar(\"%s\")", t_szBuf);
                    TrueOutputDebugStringA(t_szBuf);
                }
                TrueOutputDebugStringW(t_wstrStack.c_str());
            }
        }
        HeapFree(GetProcessHeap(), 0, t_szMultiByteStr);

        m_pcMediator->EnableSpy(TRUE);
    }

    m_pcMediator->Leave();
    return t_ret;
}

int WINAPI CCorelSpyAPIProxy::WideCharToMultiByte(UINT CodePage, DWORD dwFlags, LPCWSTR lpWideCharStr, int cchWideChar, LPSTR lpMultiByteStr, int cbMultiByte, LPCSTR lpDefaultChar, LPBOOL lpUsedDefaultChar)
{
    int t_ret;
    std::wstring t_wstrStack;
    m_pcMediator->Enter();

    t_ret = TrueWideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar, lpMultiByteStr, cbMultiByte, lpDefaultChar, lpUsedDefaultChar);
    if (TRUE == m_pcMediator->IsSpyEnabled() && cbMultiByte)
    {
        m_pcMediator->EnableSpy(FALSE);

        // Check whether it can be converted back to original string
        DWORD t_dwSize = TrueMultiByteToWideChar(CodePage, 0, lpMultiByteStr, t_ret, 0, 0);
        LPWSTR t_wszWideCharStr = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, t_dwSize*sizeof(WCHAR));
        int t_nRevert = TrueMultiByteToWideChar(CodePage, 0, lpMultiByteStr, t_ret, t_wszWideCharStr, t_dwSize);
        if (wcsncmp(lpWideCharStr, t_wszWideCharStr, t_dwSize) && 
            // A workaround for _crtLCMapStringA_stat's bug U+191 => U+192 convert problem
            ((t_dwSize != 0xff) && lpWideCharStr[0x82] != 0x191))
        {
            CONTEXT context;
            GET_CURRENT_CONTEXT(context, CONTEXT_FULL);
            m_pcMediator->GetSymbolEngine()->StackTrace(&context, 1, t_wstrStack);

            if (m_pcMediator->GetStackTraceMgr()->GetStackTraceId(t_wstrStack.c_str()) != (DWORD)-1)
            {
                {
                    WCHAR t_wszBuf[1024];
                    swprintf_s(t_wszBuf, L"[CorelSpy] There is a Unicode conversion problem in WideCharToMultiByte(\"%s\")", lpWideCharStr);
                    TrueOutputDebugStringW(t_wszBuf);
                }
                TrueOutputDebugStringW(t_wstrStack.c_str());
            }
        }
        HeapFree(GetProcessHeap(), 0, t_wszWideCharStr);

        m_pcMediator->EnableSpy(TRUE);
    }

    m_pcMediator->Leave();
    return t_ret;
}

LONG WINAPI CCorelSpyAPIProxy::RtlMultiByteToUnicodeN(PWCH UnicodeString, ULONG MaxBytesInUnicodeString, PULONG BytesInUnicodeString, const CHAR *MultiByteString, ULONG BytesInMultiByteString)
{
    LONG t_lRet;
    std::wstring t_wstrStack;
    m_pcMediator->Enter();

    t_lRet = TrueRtlMultiByteToUnicodeN(UnicodeString, MaxBytesInUnicodeString, BytesInUnicodeString, MultiByteString, BytesInMultiByteString);
    if (TRUE == m_pcMediator->IsSpyEnabled())
    {
        m_pcMediator->EnableSpy(FALSE);

        // Check whether it can be converted back to original string
        ULONG t_ulSize = 0;
        TrueRtlMultiByteToUnicodeSize(&t_ulSize, MultiByteString, BytesInMultiByteString);
        LPSTR t_szMultiByteStr = (LPSTR)HeapAlloc(GetProcessHeap(), 0, t_ulSize*sizeof(CHAR));
        ULONG t_ulBytesInmultiByteString;
        int t_nRevert = TrueRtlUnicodeToMultiByteN(t_szMultiByteStr, BytesInMultiByteString, &t_ulBytesInmultiByteString, UnicodeString, t_ulSize);
        if (strncmp(MultiByteString, t_szMultiByteStr, (t_ulSize > BytesInMultiByteString) ? BytesInMultiByteString : t_ulSize))
        {
            CONTEXT context;
            GET_CURRENT_CONTEXT(context, CONTEXT_FULL);
            m_pcMediator->GetSymbolEngine()->StackTrace(&context, 1, t_wstrStack);

            if (m_pcMediator->GetStackTraceMgr()->GetStackTraceId(t_wstrStack.c_str()) != (DWORD)-1)
            {
                TrueOutputDebugStringA("[CorelSpy] There is a Unicode conversion problem in RtlMultiByteToUnicodeN");
                TrueOutputDebugStringW(t_wstrStack.c_str());
            }
        }
        HeapFree(GetProcessHeap(), 0, t_szMultiByteStr);

        m_pcMediator->EnableSpy(TRUE);
    }

    m_pcMediator->Leave();
    return t_lRet;
}

LONG WINAPI CCorelSpyAPIProxy::RtlUnicodeToMultiByteN(PCHAR MultiByteString, ULONG MaxBytesInMultiByteString, PULONG BytesInMultiByteString, PCWCH UnicodeString, ULONG BytesInUnicodeString)
{
    LONG t_lRet;
    std::wstring t_wstrStack;
    m_pcMediator->Enter();

    t_lRet = TrueRtlUnicodeToMultiByteN(MultiByteString, MaxBytesInMultiByteString, BytesInMultiByteString, UnicodeString, BytesInUnicodeString);
    if (TRUE == m_pcMediator->IsSpyEnabled())
    {
        m_pcMediator->EnableSpy(FALSE);

        // Check whether it can be converted back to original string
        ULONG t_ulSize = 0;
        TrueRtlUnicodeToMultiByteSize(&t_ulSize, UnicodeString, BytesInUnicodeString);
        LPWSTR t_wszUnicodeStr = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, t_ulSize*sizeof(WCHAR));
        ULONG t_ulBytesInUnicodeString;
        int t_nRevert = TrueRtlMultiByteToUnicodeN(t_wszUnicodeStr, BytesInUnicodeString, &t_ulBytesInUnicodeString, MultiByteString, t_ulSize);
        if (wcsncmp(UnicodeString, t_wszUnicodeStr, t_ulSize))
        {
            CONTEXT context;
            GET_CURRENT_CONTEXT(context, CONTEXT_FULL);
            m_pcMediator->GetSymbolEngine()->StackTrace(&context, 1, t_wstrStack);

            if (m_pcMediator->GetStackTraceMgr()->GetStackTraceId(t_wstrStack.c_str()) != (DWORD)-1)
            {
                TrueOutputDebugStringA("[CorelSpy] There is a Unicode conversion problem in RtlUnicodeToMultiByteN");
                TrueOutputDebugStringW(t_wstrStack.c_str());
            }
        }
        HeapFree(GetProcessHeap(), 0, t_wszUnicodeStr);

        m_pcMediator->EnableSpy(TRUE);
    }

    m_pcMediator->Leave();
    return t_lRet;
}
